<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | 企业用户 v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-08-09
// +-------------------------------------------------------------------------------

namespace app\core\model;

use common\Random;
use think\Db;
use think\Model;

class EnterpriseDept extends Model {
    const ROOT_DEPT_ID = 1;

    public static function _q($name = false) {
        if (empty($name)) {
            $name = "enterprise_dept";
        }
        return Db::name($name);
    }

    /**
     * 获取上级部门列表
     *
     * @param $eid
     * @param $deptid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getSelfAndParents($eid, $deptid) {
        $parents = [];
        do {
            if (empty($deptid) || $deptid == self::ROOT_DEPT_ID) {
                return $parents;
            }
            $dept = self::getById($eid, $deptid);
            if (empty($dept)) {
                return $parents;
            }
            array_unshift($parents, $dept);
            $deptid = $dept['parent_id'];
        } while (true);
    }

    /**
     * 获取部门的主管列表
     *
     * @param $eid
     * @param $deptid
     * @param bool $cdu
     * @return array|bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getLeaders($eid, $deptid, $cdu = false) {
        $userids = self::_q("enterprise_dept_user")->where([
            'enterprise_id' => $eid,
            'deptid' => $deptid,
            'leader' => 1
        ])->column("userid");
        if (empty($userids)) {
            return [];
        }
        if (!$cdu) {
            return $userids;
        }

        $users = EnterpriseUser::batchById($eid, $userids);

        $cdu = [];
        foreach ($users as $user) {
            $cdu[] = [
                'id' => $user['id'],
                'type' => 'user',
                'name' => $user['showname']
            ];
        }
        return $cdu;
    }

    /**
     * 设置某个用户为部门leader
     *
     * @param $eid
     * @param $deptid
     * @param $userid
     * @param $isLeader
     * @return int|string
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function setLeader($eid, $deptid, $userid, $isLeader = true) {
        $deptUser = self::_q("enterprise_dept_user")->where([
            'enterprise_id' => $eid,
            'userid' => $userid,
            'deptid' => $deptid
        ])->find();
        if (empty($deptUser)) {
            return self::_q("enterprise_dept_user")->insertGetId([
                'enterprise_id' => $eid,
                'userid' => $userid,
                'deptid' => $deptid,
                'leader' => $isLeader ? 1 : 0
            ]);
        } else {
            if ($deptUser['leader'] == 1 && $isLeader) {
                return 1;
            }
            if ($deptUser['leader'] == 0 && !$isLeader) {
                return 1;
            }
            return self::_q("enterprise_dept_user")->where([
                'enterprise_id' => $eid,
                'userid' => $userid,
                'deptid' => $deptid
            ])->update([
                'leader' => $isLeader ? 1 : 0
            ]);
        }
    }

    /**
     * 获取用户的所在部门id列表
     *
     * @param $eid
     * @param $userid
     * @return array
     */
    public static function getUserDeptIds($eid, $userid) {
        return self::_q("enterprise_dept_user")->where([
            'enterprise_id' => $eid,
            'userid' => $userid
        ])->column("deptid");
    }

    /**
     * 判断用户是否在部门中
     *
     * @param $eid
     * @param $userid
     * @param $deptid
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function isUserInDept($eid, $userid, $deptid) {
        if ($deptid == self::ROOT_DEPT_ID) {
            return true;
        }
        $deptUser = self::_q("enterprise_dept_user")->where([
            'enterprise_id' => $eid,
            'userid' => $userid,
            'deptid' => $deptid
        ])->find();

        return empty($deptUser) ? false : true;
    }

    /**
     * 增加部门
     *
     * @param $eid
     * @param $title
     * @param $parentId
     * @return mixed|string
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function add($eid, $title, $parentId) {
        $dept = self::_q()->where([
            'enterprise_id' => $eid,
            'title' => $title,
            'parent_id' => $parentId
        ])->find();
        if (!empty($dept)) {
            self::_q()->where([
                'enterprise_id' => $eid,
                'id' => $dept['id']
            ])->update([
                'is_deleted' => 0
            ]);
            return $dept['id'];
        } else {
            $deptId = "dept_" . Random::get();
            self::_q()->insertGetId([
                'enterprise_id' => $eid,
                'id' => $deptId,
                'title' => $title,
                'parent_id' => $parentId,
                'gmt_created' => time(),
                'gmt_modified' => time()
            ]);
            return $deptId;
        }
    }

    /**
     * 获取部门及子部门id列表
     *
     * @param $eid
     * @param $deptid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getSelfAndSubDeptIds($eid, $deptid) {
        $deptTree = self::getTree($eid);
        $deptTreeItem = self::_getTreeItem($deptTree, $deptid);
        return self::_getDeptIds($deptTreeItem);
    }

    /**
     * 获取部门id与部门全路径的对照表
     *
     * @param $eid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @return array
     */
    public static function getDeptidTitleMapping($eid) {
        $deptTree = self::getTree($eid);

        $mapping = [];
        foreach ($deptTree as $deptTreeItem) {
            self::_generateDeptTreeItemMapping($deptTreeItem, "", $mapping);
        }
        return $mapping;
    }

    private static function _generateDeptTreeItemMapping($deptTreeItem, $prefixTitle, &$mapping) {
        $title = $deptTreeItem['title'];
        if (!empty($prefixTitle)) {
            $title = $prefixTitle . "/" . $title;
        }
        $mapping[$deptTreeItem['id']] = $title;

        if (isset($deptTreeItem['childs'])) {
            foreach ($deptTreeItem['childs'] as $subDeptTreeItem) {
                self::_generateDeptTreeItemMapping($subDeptTreeItem, $title, $mapping);
            }
        }
    }

    /**
     * 删除部门
     *
     * @param $eid
     * @param $deptid
     * @return int|string
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public static function del($eid, $deptid) {
        $deptids = self::getSelfAndSubDeptIds($eid, $deptid);

        return self::_q()->where([
            'enterprise_id' => $eid,
            'id' => ['in', $deptids]
        ])->update([
            'is_deleted' => 1
        ]);
    }

    private static function _getTreeItem($deptTreeItems, $deptid) {
        if (empty($deptTreeItems)) {
            return false;
        }
        foreach ($deptTreeItems as $id => $deptTreeItem) {
            if ($deptid == $id) {
                return $deptTreeItem;
            }
            if (empty($deptTreeItem['childs'])) {
                continue;
            }
            //到子节点中查找
            $item = self::_getTreeItem($deptTreeItem['childs'], $deptid);
            if (!$item) {
                continue;
            } else {
                return $item;
            }
        }
        return false;
    }

    private static function _getDeptIds($deptTreeItem) {
        $deptids = [$deptTreeItem['id']];
        if (empty($deptTreeItem['childs'])) {
            return $deptids;
        }
        foreach ($deptTreeItem['childs'] as $subDeptTreeItem) {
            $deptids = array_merge($deptids, self::_getDeptIds($subDeptTreeItem));
        }
        return $deptids;
    }

    /**
     * 获取部门信息
     *
     * @param $eid
     * @param $deptid
     * @return array|false|\PDOStatement|string|Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getById($eid, $deptid) {
        return self::_q()->where([
            'enterprise_id' => $eid,
            'id' => $deptid,
            'is_deleted' => 0
        ])->find();
    }

    /**
     * 通过id批量获取部门信息
     *
     * @param $eid
     * @param $deptids
     * @return array|false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function batchGetByIds($eid, $deptids) {
        if (empty($deptids)) {
            return [];
        }
        return self::_q()->where([
            'enterprise_id' => $eid,
            'id' => ['in', $deptids],
            'is_deleted' => 0
        ])->select();
    }

    /**
     * 更新部门信息
     *
     * @param $eid
     * @param $deptid
     * @param $data
     * @return int|string
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public static function updateById($eid, $deptid, $data) {
        $data['gmt_modified'] = time();
        return self::_q()->where([
            'enterprise_id' => $eid,
            'id' => $deptid,
            'is_deleted' => 0
        ])->update($data);
    }

    /**
     * 获取企业的所有部门
     *
     * @param $eid
     * @return false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getAll($eid) {
        return self::_q()->where([
            'enterprise_id' => $eid,
            'is_deleted' => 0
        ])->select();
    }

    /**
     * 获取部门树形结构
     *
     * @param $eid
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getTree($eid) {
        $depts = self::getAll($eid);

        $deptTree = [];
        do {
            $failedInsertDepts = [];
            foreach ($depts as $idx => $dept) {
                if (empty($dept['parent_id']) || $dept['parent_id'] == self::ROOT_DEPT_ID) {
                    $deptTree[$dept['id']] = $dept;
                } else {
                    $inserted = false;
                    foreach ($deptTree as &$deptTreeItem) {
                        if (self::_insertToDeptTree($deptTreeItem, $dept)) {
                            $inserted = true;
                            break;
                        }
                    }
                    if (!$inserted) {
                        $failedInsertDepts[] = $dept;
                    }
                }
            }

            if (empty($failedInsertDepts)) {
                break;
            }
            if (count($failedInsertDepts) == count($depts)) {
                break;
            }
            $depts = $failedInsertDepts;
        } while (true);

        return $deptTree;
    }

    /**
     * 将节点插入树种
     *
     * @param $deptTreeItem
     * @param $dept
     * @return bool
     */
    private static function _insertToDeptTree(&$deptTreeItem, $dept) {
        $parentId = $dept['parent_id'];
        if (!isset($deptTreeItem['childs'])) {
            $deptTreeItem['childs'] = [];
        }

        if ($deptTreeItem['id'] == $parentId) {
            $deptTreeItem['childs'][$dept['id']] = $dept;
            return true;
        } else {
            foreach ($deptTreeItem['childs'] as &$childDeptTreeItem) {
                if (self::_insertToDeptTree($childDeptTreeItem, $dept)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 从钉钉同步部门信息
     *
     * @param $dingDept
     * @param $eid
     * @return int|string
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function syncDing($dingDept, $eid) {
        $dept = self::_q()->where([
            'enterprise_id' => $eid,
            'id' => $dingDept['id']
        ])->find();
        if (empty($dept)) {
            return self::_q()->insertGetId([
                'enterprise_id' => $eid,
                'id' => $dingDept['id'],
                'title' => $dingDept['name'],
                'parent_id' => $dingDept['parentid'],
                'gmt_created' => time(),
                'gmt_modified' => time()
            ]);
        } else {
            return self::_q()->where([
                'enterprise_id' => $eid,
                'id' => $dingDept['id']
            ])->update([
                'title' => $dingDept['name'],
                'parent_id' => $dingDept['parentid'],
                'gmt_modified' => time(),
                'is_deleted' => 0
            ]);
        }
    }

    /**
     * 将用户添加到部门
     *
     * @param $eid
     * @param $userid
     * @param $deptId
     * @param null $isLeader
     * @param null $order
     * @return int|string
     */
    public static function addUserToDept($eid, $userid, $deptId, $isLeader = null, $order = null) {
        $data = [
            'enterprise_id' => $eid,
            'userid' => $userid,
            'deptid' => $deptId
        ];
        if ($isLeader !== null) {
            $data['leader'] = $isLeader;
        }
        if ($order !== null) {
            $data['order'] = $order;
        }
        return self::_q("enterprise_dept_user")->insertGetId($data, true);
    }

    /**
     * 将用户从部门移除
     *
     * @param $eid
     * @param $userid
     * @param $deptId
     * @return int
     * @throws \think\Exception
     * @throws \think\exception\PDOException
     */
    public static function removeUserFromDept($eid, $userid, $deptId) {
        return self::_q("enterprise_dept_user")->where([
            'enterprise_id' => $eid,
            'userid' => $userid,
            'deptid' => $deptId
        ])->delete();
    }

    /**
     * 获取子部门
     *
     * @param $eid
     * @param $parentDepartmentId
     * @return false|\PDOStatement|string|\think\Collection
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function getSubDepts($eid, $parentDepartmentId) {
        $query = self::_q("enterprise_dept");
        $query->where([
            'enterprise_id' => $eid,
            'is_deleted' => 0
        ]);

        if (empty($parentDepartmentId) || $parentDepartmentId == self::ROOT_DEPT_ID) {
            $query->where("(parent_id is null or parent_id = " . self::ROOT_DEPT_ID . ")");
        } else {
            $query->where([
                'parent_id' => $parentDepartmentId
            ]);
        }

        return $query->select();
    }
}